package com.multiplay.tetris;

import android.util.Log;

import com.multiplay.GlobalDefs;

public class GameBlock 
{
	protected static final int EMPTY_FIELD = 0xFFFF;
	protected static final int [][] rotate_4_x = 
		{{EMPTY_FIELD, 1, EMPTY_FIELD, EMPTY_FIELD}, {-1, 0, 1, 2},
		{EMPTY_FIELD, -1, EMPTY_FIELD, EMPTY_FIELD},
		{EMPTY_FIELD, -2, EMPTY_FIELD, EMPTY_FIELD}};
	protected static final int [][] rotate_4_y = 
		{{EMPTY_FIELD, -1, EMPTY_FIELD, EMPTY_FIELD}, {1, 0, -1, -2},
		{EMPTY_FIELD, 1, EMPTY_FIELD, EMPTY_FIELD},
		{EMPTY_FIELD, 2, EMPTY_FIELD, EMPTY_FIELD}};
	protected static final int [][] rotate_3_x =
		{{2, 1, 0}, {1, 0, -1}, {0, -1, -2}};
	protected static final int [][] rotate_3_y =
		{{0, -1, -2}, {1, 0, -1}, {2, 1, 0}};
	
	protected int block_type;
	protected int block_matrix_size;
	protected int [][] block_matrix = null;
	protected int [] block_coord = new int[8];
	protected int [][] temp_block_state = null;
	
	protected GameBlock(int type) throws Exception
	{
		block_type = type;
		
		switch (type)
		{
		case 0:
			block_matrix_size = 4;
			break;
		case 3:
			block_matrix_size = 2;
			break;
		case 1:
		case 2:
		case 4:
		case 5:
		case 6:
			block_matrix_size = 3;
			break;
		default:
			throw(new Exception(new String("Invalid block type: " + type)));
		}
		block_matrix = new int[block_matrix_size][block_matrix_size];
		
		clear_block(block_matrix, block_matrix_size);
		fill_block();
	}
	
	protected static void clear_block(int [][] block, int size)
	{
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
				block[i][j] = EMPTY_FIELD;
	}
	
	protected static void copy_block(int [][] src, int [][] dst, int size)
	{
		for (int i = 0; i < size; i++)
			for (int j = 0; j < size; j++)
				dst[i][j] = src[i][j];
	}
	
	protected int get_x(int pair)
	{
		return (pair & 0x000000FF);
	}
	
	protected int get_y(int pair)
	{
		return ((pair & 0x0000FF00) >> 8);
	}
	
	protected int set_pair(int x, int y)
	{
		return ((x & 0xFF) | ((y & 0xFF) << 8));
	}
	
	protected int set_pair_x(int pair, int x)
	{
		pair &= ~0xFF;
		return (pair | (x & 0xFF));
	}
	
	protected int set_pair_y(int pair, int y)
	{
		pair &= ~0xFF00;
		return (pair | ((y & 0xFF) << 8));
	}
	
	protected void fill_block_0()
	{
		block_matrix[1][0] = set_pair(5, 0);
		block_matrix[1][1] = set_pair(5, 1);
		block_matrix[1][2] = set_pair(5, 2);
		block_matrix[1][3] = set_pair(5, 3);
	}
	
	protected void fill_block_1()
	{
		block_matrix[1][0] = set_pair(4, 0);
		block_matrix[1][1] = set_pair(4, 1);
		block_matrix[1][2] = set_pair(4, 2);
		block_matrix[2][2] = set_pair(5, 2);
	}
	
	protected void fill_block_2()
	{
		block_matrix[1][0] = set_pair(5, 0);
		block_matrix[1][1] = set_pair(5, 1);
		block_matrix[1][2] = set_pair(5, 2);
		block_matrix[0][2] = set_pair(4, 2);
	}
	
	protected void fill_block_3()
	{
		block_matrix[0][0] = set_pair(4, 0);
		block_matrix[1][0] = set_pair(5, 0);
		block_matrix[0][1] = set_pair(4, 1);
		block_matrix[1][1] = set_pair(5, 1);
	}
	
	protected void fill_block_4()
	{
		block_matrix[1][0] = set_pair(5, 0);
		block_matrix[1][1] = set_pair(5, 1);
		block_matrix[1][2] = set_pair(5, 2);
		block_matrix[0][1] = set_pair(4, 1);
	}
	
	protected void fill_block_5()
	{
		block_matrix[1][0] = set_pair(5, 0);
		block_matrix[1][1] = set_pair(5, 1);
		block_matrix[0][1] = set_pair(4, 1);
		block_matrix[0][2] = set_pair(4, 2);
	}
	
	protected void fill_block_6()
	{
		block_matrix[0][0] = set_pair(4, 0);
		block_matrix[0][1] = set_pair(4, 1);
		block_matrix[1][1] = set_pair(5, 1);
		block_matrix[1][2] = set_pair(5, 2);
	}
	
	protected void fill_block()
	{
		switch (block_type)
		{
		case 0:
			fill_block_0();
			break;
		case 1:
			fill_block_1();
			break;
		case 2:
			fill_block_2();
			break;
		case 3:
			fill_block_3();
			break;
		case 4:
			fill_block_4();
			break;
		case 5:
			fill_block_5();
			break;
		case 6:
			fill_block_6();
			break;
		default:
			break;
		}
	}
	
	protected boolean prepare_new_position()
	{
		int x, y, dx, dy;
		
		temp_block_state = new int[block_matrix_size][block_matrix_size];
		clear_block(temp_block_state, block_matrix_size);
		
		for (int i = 0; i < block_matrix_size; i++)
		{
			for (int j = 0; j < block_matrix_size; j++)
			{
				if (block_matrix[i][j] != EMPTY_FIELD)
				{
					x = get_x(block_matrix[i][j]);
					y = get_y(block_matrix[i][j]);
					if (block_matrix_size == 4)
					{
						dx = rotate_4_x[i][j];
						dy = rotate_4_y[i][j];
					}
					else
					{
						dx = rotate_3_x[i][j];
						dy = rotate_3_y[i][j];
					}
					
					if (block_matrix_size == 4)
					{
						if (x + dx < 0 || x + dx > PlayFieldView.CUP_WIDTH)
							return false;
					}
					else
					{
						if (x + dx < 0 || x + dx >= PlayFieldView.CUP_WIDTH)
							return false;
					}
					if (y + dy > PlayFieldView.CUP_HEIGHT)
						return false;
					
					temp_block_state[i + dx][j + dy] = set_pair(x + dx, y + dy);
				}
			}
		}
		return true;
	}
	
	protected boolean rotate_3x3()
	{
		return prepare_new_position();
	}
	
	protected boolean rotate_4x4()
	{
		int x, y;
		
		if (!prepare_new_position())
			return false;
		
		if (temp_block_state[3][1] != EMPTY_FIELD)
		{
			x = get_x(temp_block_state[3][1]);
			if (x == PlayFieldView.CUP_WIDTH)
			{
				for (int i = 0; i < 4; i++)
				{
					x = get_x(temp_block_state[i][1]);
					x--;
					temp_block_state[i][1] = set_pair_x(temp_block_state[i][1], x);
				}
			}
		}
		if (temp_block_state[1][3] != EMPTY_FIELD)
		{
			y = get_y(temp_block_state[1][3]);
			if (y == PlayFieldView.CUP_HEIGHT)
			{
				for (int i = 0; i < 4; i++)
				{
					y = get_y(temp_block_state[1][i]);
					y--;
					temp_block_state[1][i] = set_pair_y(temp_block_state[1][i], y);
				}
			}
		}
		
		return true;
	}
	
	public int [] get_rotated_block_data()
	{
		int count = 0;
		
		if (temp_block_state == null)
			return null;
		
		int [] coord = new int [8];
		for (int i = 0; i < block_matrix_size; i++)
		{
			for (int j = 0; j < block_matrix_size; j++)
			{
				if (temp_block_state[i][j] != EMPTY_FIELD)
				{
					coord[2 * count] = get_x(temp_block_state[i][j]);
					coord[2 * count + 1] = get_y(temp_block_state[i][j]);
					count++;
				}
			}
		}
		
		return coord;
	}
	
	public void finish_rotation(boolean set)
	{
		if (set)
			copy_block(temp_block_state, block_matrix, block_matrix_size);
		
		temp_block_state = null;
	}
	
	public boolean prepare_rotation()
	{
		boolean rc;
		
		switch (block_type)
		{
		case 0:
			rc = rotate_4x4();
			break;
		case 1:
		case 2:
		case 4:
		case 5:
		case 6:
			rc = rotate_3x3();
			break;
		case 3:
			rc = true;
			break;
		default:
			rc = false;
			break;
		}
		
		return rc;
	}
	
	public int[] get_block_coord()
	{
		int count = 0;
		
		for (int i = 0; i < block_matrix_size; i++)
		{
			for (int j = 0; j < block_matrix_size; j++)
			{
				if (block_matrix[i][j] != EMPTY_FIELD)
				{
					block_coord[2 * count] = get_x(block_matrix[i][j]);
					block_coord[2 * count + 1] = get_y(block_matrix[i][j]);
					count++;
				}
			}
		}
		
		return block_coord;
	}
	
	public void move_down(int deep)
	{
		int y;
		for (int i = 0; i < block_matrix_size; i++)
		{
			for (int j = 0; j < block_matrix_size; j++)
			{
				if (block_matrix[i][j] != EMPTY_FIELD)
				{
					y = get_y(block_matrix[i][j]);
					y += deep;
					block_matrix[i][j] = set_pair_y(block_matrix[i][j], y);
				}
			}
		}
	}
	
	public void step_left()
	{
		int x;
		for (int i = 0; i < block_matrix_size; i++)
		{
			for (int j = 0; j < block_matrix_size; j++)
			{
				if (block_matrix[i][j] != EMPTY_FIELD)
				{
					x = get_x(block_matrix[i][j]);
					x--;
					block_matrix[i][j] = set_pair_x(block_matrix[i][j], x);
				}
			}
		}
	}
	
	public void step_rigth()
	{
		int x;
		for (int i = 0; i < block_matrix_size; i++)
		{
			for (int j = 0; j < block_matrix_size; j++)
			{
				if (block_matrix[i][j] != EMPTY_FIELD)
				{
					x = get_x(block_matrix[i][j]);
					x++;
					block_matrix[i][j] = set_pair_x(block_matrix[i][j], x);
				}
			}
		}
	}
	
	public int get_type()
	{
		return block_type;
	}
	
	static public GameBlock create_block(int type)
	{
		GameBlock block = null;
		
		try 
		{
			block = new GameBlock(type);
		}
		catch (Exception e) 
		{
			Log.v(GlobalDefs.LOG_APP_TAG, e.getMessage());
		}
		
		return block;
	}
}
